home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Utilities / Text Processing / Alpha / Help / Extending Alpha < prev    next >
Encoding:
Text File  |  1997-12-18  |  40.6 KB  |  1,038 lines  |  [TEXT/ALFA]

  1.  
  2.                     Writing New Modes, Menus and Packages
  3.  
  4.  
  5.                                               created: 3/3/97 {12:44:50 pm}
  6.                                           last update: 18/12/97 {10:23:26 pm}
  7.  
  8. Author:    Vince Darley, some pieces by Tom Fetherston and Pete Keleher
  9. E-mail:    <darley@fas.harvard.edu>
  10.   mail:    Division of    Engineering and Applied    Sciences, Harvard University
  11.         Oxford Street, Cambridge MA    02138, USA
  12.    www:    <http://www.fas.harvard.edu/~darley/>
  13.  
  14.  
  15.            Introduction
  16.  
  17. If you're writing or modifying any mode, menu or extension (collectively 
  18. known as packages) related Tcl code for use with Alpha, you should read this 
  19. document.  It also tells you how to make use of some of the features of 
  20. Vince's Additions in your mode.  These instructions pertain to all versions 
  21. of Alpha greater than or equal to 7.0.
  22.  
  23. There are three types of package which Alpha uses: modes, menus and 
  24. extensions.  A mode helps with editing a file for a particular purpose: web 
  25. pages use 'HTML' mode, C++ code uses 'C++' mode, LaTeX documents use 'TeX' 
  26. mode,… There are about 20 such modes currently available.  Menus are of two 
  27. types: mode-menus and global menus.  Any global menu may also be a mode menu 
  28. and any mode menu may also be a global menu, but there is a useful 
  29. functional distinction: mode menus are only really useful when you are 
  30. editing a document associated with that mode.  Global menus are useful at 
  31. any time, independent of the mode.  Alpha designates such menus 'package 
  32. menus', and has a separate menu for them allowing you to switch them on and 
  33. off easily.  Examples of package menus are the filesets menu, the eudora 
  34. menu and the electric menu.  When you create a new menu for Alpha, you have 
  35. the option of making it a package menu or not.  Finally, the third type of 
  36. Alpha package is the extension.  This is a piece of code which may be 
  37. turned on or off by the user independently of the current mode.  Examples of 
  38. extensions are Vince's Additions, the printer choices sub-menu, or the 
  39. bib-engine (used to interact with BibTeX).
  40.  
  41. For the impatient reader: here's how to write a very simple extension 
  42. which contains one new procedure and one new key-binding (to that 
  43. procedure).  Just create a file which looks like this:
  44.  
  45.     # (auto-install) --- this line will cause Alpha to try to install 
  46.     # this pkg when this file is opened outside of Alpha's folder hierarchy
  47.     
  48.     alpha::extension myPackage 0.1 {
  49.         # bind the 'x' key to my procedure (not a good idea ;-)
  50.         bind 'x' myProcedure
  51.     } uninstall {this-file} maintainer {
  52.         "My Name" my@email http://webpage..
  53.     } help {
  54.         Binds the blah-key to 'myProcedure' which carries out...
  55.     }
  56.     
  57.     proc myProcedure {} {
  58.         # do some cool stuff
  59.     }
  60.     
  61. Save this file on your desktop (say), and open it.  You'll see Alpha
  62. automatically opens an installation dialog, puts this file in the
  63. right place if you agreed to the installation, and rebuilds its
  64. package and tcl indices so that this package can be used next time
  65. you restart Alpha (actually with a simple package like this, you can
  66. use it straight-away).
  67.  
  68. Alpha provides lots of cool features to help you write useful
  69. packages, whether they are modes, menus or extensions.  This
  70. document describes those features.
  71.  
  72.              Declaring your package to Alpha
  73.  
  74. A package must contain, preferably as its first non-comment line (this 
  75. is important), a statement like this:
  76.  
  77.     alpha::mode NAME VERSION ...
  78.     
  79.     alpha::menu NAME VERSION ...
  80.     
  81.     alpha::extension NAME VERSION ...
  82.     
  83. (The other parameters to these commands are explained below).  The name will 
  84. identify your package, and for modes must be at most 4 characters long.  
  85. It should not contain any spaces (this limitation may be lifted in a future 
  86. version of Alpha).  The version is a string of the form 1.0.1, or 2.3b1 or 
  87. 1.4.530.1.3a5.  Modes, menus and extensions take different arguments for the 
  88. remainder of the 'alpha::' declaration line, but each ends in a script which 
  89. Alpha scans and stores for you (Alpha scans all installed files for 
  90. package declaration lines and caches this information so that at startup, 
  91. no files need be read).  For modes and menus, this script is executed 
  92. automatically at startup.  For extensions, the script is only executed if 
  93. that extension has been activated by the user.  Package initialisation 
  94. occurs in the order: modes, menus and finally extensions.
  95.  
  96. IMPORTANT: The declaration command must be at the beginning of the line, and 
  97. it must not be wrapped in any 'catch' statements.  This is necessary to 
  98. allow Alpha to rebuild package indices rapidly.  If you wish to write 
  99. backwards compatible code, try something like:
  100.  
  101.     if {[info commands alpha::extension] != ""} {
  102.     alpha::extension ...
  103.     } else {
  104.         # initialise in some old way
  105.     }
  106.  
  107. Your package will not function properly if you don't obey the above 
  108. guidelines.  Alpha itself is considered a package, with a version
  109. number, so that your code can request a particular version of Alpha.
  110. Alpha's version number also has a patchlevel which will be updated
  111. with each Tcl-only patch release.  Hence you can write:
  112.  
  113.     alpha::package require Alpha 7.0b1
  114.  
  115. For the first Alpha 7.0 release, and
  116.  
  117.     alpha::package require Alpha 7.0b1p1
  118.  
  119. If your package actually requires some fixes from the first patch release.
  120. You can similarly require particular versions of other packages.  You
  121. should 'require' as old a version as possible, so that you don't force
  122. users to upgrade unnecessarily.
  123.  
  124. Note that with the advent of the new alpha:: commands, it is no longer
  125. necessary to place modes, menus and packages in their separate directories:
  126. they can go anywhere on the auto-path.  However it is more convenient to
  127. store them separately most of the time.
  128.  
  129.              The developer utilities package
  130.  
  131. You will want to download this package, since it helps with a number
  132. of developer-related tasks:
  133.  
  134. •    distribution archival, compression, and uploading
  135. •    colouring and hyperlinking Help files (like this one)
  136.  
  137. For anyone helping with Alpha's core distribution it also allows:
  138.  
  139. •    colouring Alpha's manual, commands, readme and changes files
  140.  
  141. ===============================================================================
  142.            
  143.            Writing New Modes
  144.  
  145. To add a mode to Alpha, a file (usually ending with 'Mode.tcl') must be 
  146. created and placed in the ":Tcl:Modes" directory.
  147.  
  148. The file should begin with a construct of the following form:
  149.  
  150.     alpha::mode Perl 1.3 dummyPerl {*.pl *.ph *.pm} perlMenu {
  151.         addMenu perlMenu •132
  152.     }
  153.  
  154. This command is very, very important.
  155.  
  156.     alpha::mode <mode> <version> <dummyProc> <suffixes> <mode-menus> <script>
  157.     
  158. defines a new mode.  When trying to switch to the Perl mode, Alpha will 
  159. attempt to execute the function 'dummyPerl'.  The suffixes allow Alpha to 
  160. automatically determine the correct mode of a newly opened file.  In this
  161. case the script contains the single command:
  162.  
  163.     addMenu <mname> <name>
  164.  
  165. which defines a new menu, with 'name' the visible name of the menu (names 
  166. which start with '•' indicate Alpha should use an icon resource with the 
  167. given number.  Icon number 132 is the Perl camel icon).  This menu can be 
  168. used in any mode, although by default, it is only attached to Perl mode.  
  169. 'mname' is actually a variable which contains (will contain) the real menu 
  170. name (in this case '•132').
  171.  
  172. Perhaps the MOST important part of the above code is the existence of the
  173. 'dummyProc'.  When this proc is called, the result must be that all of 
  174. the mode's preferences are declared.  In other words, the dummyProc
  175. should normally be in the same file as the mode's 'newPref' declarations.
  176. This is important because almost directly after that call, Alpha expects
  177. all of the mode's preferences to be stored in the ${mode}modeVars array,
  178. which will only be true if all of the newPref commands have been evaluated.
  179.  
  180. Here is an example from Diff mode:
  181.  
  182.     alpha::mode Diff 1.0 diffMenu {*.diff} {diffMenu} {
  183.         addMenu diffMenu •288
  184.         menu::insert Utils submenu 0 compare
  185.         menu::insert compare items end "windows" "files…" "directories…"
  186.     } uninstall {
  187.         removeFile "$pkg_file"
  188.         removeFile "${HOME}:Tools:GNU Diff"
  189.     } maintainer { "Vince Darley" darley@fas.harvard.edu http://... }
  190.  
  191. The 'uninstall' and 'maintainer' sections are optional, and explained later.  
  192. Here is a more complex example for Python mode:
  193.  
  194.     # ◊◊◊◊ minalmalist mode set-up ◊◊◊◊ #
  195.     alpha::mode Pyth 0.2 dummyPython {*.py *.pyc *.pyi} PythonMenu {
  196.         addMenu PythonMenu
  197.         #To set the mode from a unix-like "#!python" first line
  198.         set unixMode(python) {Pyth}
  199.     }
  200.     # dummy proc to load this mode.  
  201.     proc dummyPython {} {}
  202.     # dummy proc to load the code to make the PythonMenu 
  203.     proc PythonMenu {} {}
  204.     # rest of mode's code follows...
  205.     
  206.     #Let the automatic comment insertion/continuation
  207.     # routines function with this mode. 
  208.     set Pyth::commentCharacters(General) "\#"
  209.     set Pyth::commentCharacters(Paragraph) [list "## " " ##" " # "]
  210.     set Pyth::commentCharacters(Box) [list "#" 1 "#" 1 "#" 3]
  211.     
  212. The package declaration should contain all code which is necessary to 
  213. recognise a given file as belonging to that mode (hence the use
  214. of 'unixMode' for python), which will then make Alpha call the
  215. dummyProc which will auto-load the entire file.  Other information,
  216. such as the 'commentCharacters' entries above should not go in the
  217. package declaration.
  218.     
  219. Notice that there are two types of 'dummy' proc: each menu Alpha uses
  220. should have a proc of the same name associated with it.  This proc is
  221. called by Alpha _each_ time Alpha tries to insert the menu into the
  222. menubar.  The proc can be empty (as above), or could actually do
  223. something if desired.  The second kind of dummy proc is the 'mode'
  224. dummy proc, given in the 'alpha::mode' command.  Here it is called
  225. 'dummyPython'.  Alpha calls this proc each time it switches to Pyth
  226. mode.  Again the proc can do something if desired, but will usually
  227. be empty.  If both procs are empty, as above, one can of course
  228. just use one proc (called PythonMenu in this case), and replace the
  229. alpha::mode line by:
  230.  
  231.     alpha::mode Pyth 0.2 PythonMenu {*.py *.pyc *.pyi} PythonMenu
  232.  
  233. The only advantage of this approach is that it saves a small amount
  234. of memory (you can delete the 'dummyPython' proc from the file).
  235.     
  236.              Multi-file modes
  237.  
  238. Modes that consist of more than a single file should no longer use a source 
  239. statement that assumes that the other files for the mode will be in 
  240. $HOME:Tcl:Modes.  The best solution is to use Alpha's standard auto-loading 
  241. capability which will source a file when it needs a procedure which is 
  242. contained in that file.  If you must use 'source' manually, you can use 
  243. 'file dirname [procs::find someProcInThisFile]' to get the current 
  244. directory.  Your other files should also be there.
  245.  
  246. A convenient way of implementing your multi-file loading is to create
  247. procs with the same name as the file at the beginning of each file.
  248. Then to load the file you just do 'catch "filename"'.  For example
  249. if there is a proc defined 'proc perl4.tcl {} {}' at the start of
  250. the file "perl4.tcl", then I can auto-load that file with:
  251.  
  252.     if [catch perl4.tcl] { 
  253.         alertnote "Problem loading 'perl4.tcl'" 
  254.     }
  255.  
  256. Remember, you don't necessarily need to source all your mode/pkg's files in 
  257. one go.  Tcl is designed to source files for you when they are needed (when 
  258. a procedure contained in one of them is called).  Hence you only need to 
  259. source files which are required immediately (to set up some data, variables, 
  260. menus etc.)  and not everything else.  It is usually best to have a single 
  261. file which contains all the initialisation code, and let any other files be 
  262. auto-loaded as necessary.
  263.  
  264.              Mode procs
  265.  
  266. The following procs are either required or desired for a mode to be
  267. fully functional within Alpha.
  268.  
  269.     <mode>::MarkFile
  270.     <mode>::parseFuncs
  271.     
  272.     <mode>::DblClick
  273.     
  274.     <mode>::optionTitlebar
  275.     <mode>::optionTitlebarSelect
  276.     
  277.     <mode>::indentLine
  278.     <mode>::electricLeft
  279.     <mode>::electricRight
  280.     <mode>::correctIndentation
  281.     <mode>::carriageReturn
  282.  
  283. Have a look at a standard mode like Tcl or C++ to see what these
  284. should do.  <mode>::correctIndentation must not fail.
  285.     
  286.              Hooks
  287.  
  288. Do not do all that 'rename saveHook mySaveHook'... stuff.  Use 
  289. 'hook::register' instead. See the file "hook.tcl" for details, but all
  290. you need to do is add lines like these:
  291.  
  292.     hook::register saveHook modified "C" "C++"
  293.     hook::register saveHook modified "Pasc"
  294.     hook::register saveHook htmlLastModified HTML
  295.     hook::register savePostHook codeWarrior_modified "C++" "C"
  296.     hook::register savePostHook ftpPostHook
  297.     hook::register saveasHook htmlLastModified HTML
  298.  
  299. Here's the general form
  300.  
  301.     hook::register 'hook-name' 'your proc' 'mode' ?... 'mode'?
  302.  
  303. If you don't include a 'mode', then your proc will be called no
  304. matter what the current mode is.   Avoid this unless absolutely
  305. necessary.  Here are the current hooks:
  306.  
  307.     activateHook changeMode closeHook deactivateHook modifyModeFlags 
  308.     quitHook resumeHook saveasHook saveHook savePostHook suspendHook
  309.     openHook
  310.  
  311. There's also a 'mode::init' hook which will be called the first
  312. time a mode is started up.  Note that the mode exists, but its
  313. variables have not yet been made global, and its menus have not
  314. yet been inserted into the menu bar.
  315.  
  316. There's also a 'startupHook' which is called when Alpha starts
  317. up, but after all other initialisation has taken place, a 'launch'
  318. hook which is called when Alpha launches another application
  319. (register with hook::register launch yourproc $sig).
  320.  
  321.              Smart mode lines
  322.     
  323. If your mode will want to be able to use the first line of a file to 
  324. determine what mode a file should be opened up in, you need to tell 
  325. alpha what word in the first line should trigger that mode:
  326.     
  327.     set unixMode(python) {Pyth} 
  328.  
  329. A good place to do this is in the body of the your mode's package 
  330. declaration "alpha::mode … {…" statement (see example for Python above).  
  331. Note that the presence of the word itself is not sufficient; it must be of 
  332. the form '#!\usr\..\python' as is common on Unix (where it tells the shell 
  333. with what application to run the script)
  334.  
  335.              Mode creator types
  336.     
  337. If your mode wants to declare itself as a default for files with a 
  338. particular creator, you need to tell Alpha with an entry like this:
  339.     
  340.     set modeCreators(GPLT) GPLT
  341.  
  342. A good place to do this is in the body of the your mode's package 
  343. declaration "alpha::mode … {…" statement.
  344.  
  345.              Comment characters
  346.  
  347. If your mode will want to use the standard Alpha comment/uncomment
  348. block procedures, file headers, ... you need to tell Alpha what
  349. characters are used for comments.  Rather than redefining 
  350. the procedure 'commentCharacters', you should just define the following 
  351. variables:
  352.     
  353.     set commentCharacters(${mode}:General) [list "*" "//"]
  354.     set commentCharacters(${mode}:Paragraph) [list "/* " " */" " * "]
  355.     set commentCharacters(${mode}:Box) [list "/*" 2 "*/" 2 "*" 3]
  356.  
  357. or
  358.  
  359.     set ${mode}::commentCharacters(General) [list "*" "//"]
  360.     set ${mode}::commentCharacters(Paragraph) [list "/* " " */" " * "]
  361.     set ${mode}::commentCharacters(Box) [list "/*" 2 "*/" 2 "*" 3]
  362.     
  363. where the values shown are for C++ mode.  If you do this then there is
  364. no need to mess with the commentCharacters procedure.  (In general it
  365. is best if your mode does not need to redefine procedures in Alpha's core).
  366.  
  367.              Paragraph definitions
  368.  
  369. Paragraph filling.  You can set the variables:
  370.  
  371.     set ${mode}::startPara {^(.*\{)?[ \t]*$}
  372.     set ${mode}::endPara {^(.*\})?[ \t]*$}
  373.  
  374. to customize your mode's paragraph definition.  This example is for Tcl
  375. mode.
  376.  
  377.              Electric braces and semicolon
  378.  
  379. If your mode uses electric '{', '}', ';' (i.e. characters that end the 
  380. current line and indent the next one automatically)  you need to define  
  381. a few mode variables, for instance like this:
  382.  
  383.     newPref flag elecRBrace 1 C++
  384.     newPref flag electricSemi 1 C++
  385.     newPref flag elecLBrace 1 C++
  386.     
  387. Then you just need to define any of the procedures '${mode}::electricLeft',
  388. '${mode}::electricRight' and '${mode}::electricSemi' which will be called
  389. automatically (you do NOT need to bind anything to the keys).  If you do
  390. not define these procedures, Alpha will use a default electric procedure
  391. which works pretty well for C, Perl and Java code.
  392.  
  393. Do not bind to '{', '}' or ';' if you want these to be electric. Alpha
  394. will automatically call your mode's procedures if they are named
  395. correctly.
  396.  
  397.              Option-click-titlebar menu
  398.  
  399. If your mode has a specific 'opt-titlebar-click' menu, you need to
  400. define the procedures:
  401.     
  402.     proc C++::OptionTitlebar {} {
  403.         # returns list of items for the menu
  404.     }
  405.     proc C++::OptionTitlebarSelect {item} {
  406.         # carries out the mode-specific action when 'item' is selected.
  407.     }
  408.  
  409.              Electric code templates
  410.     
  411. If you mode wants to insert text into the window which contains template 
  412. stops (usually bullets '•' in Alpha), so that the user can move from
  413. one to the next using the standard Alpha template packages (Alpha comes with 
  414. a basic one, and more sophisticated ones build upon the same 
  415. infrastructure), the you should insert template text with:
  416.  
  417.     elec::Insertion "blah blah •• blah blah"
  418.  
  419. This is a simple example with a single template stop.  Template stops are 
  420. noted with a pair of bullets (even though only one appears in the text).  
  421. You can place between the pair of bullets some more information about the 
  422. template stop, for instance:
  423.  
  424.     elec::Insertion "while \{•condition•\} \{\r\t•while body•\r\}\r••"
  425.  
  426. would be useful to insert a typical Tcl 'while' loop.  The template
  427. packages can prompt the user with the explanatory text making code 
  428. entry a little bit easier.
  429.  
  430. The 'elec::Insertion' routine works just like 'insertText' except it treats 
  431. any item •PROMPT• as a template stop called 'PROMPT'.  This procedure takes 
  432. a variable number of arguments, just like 'insertText'.  It has one further 
  433. side-effect.  If there are any stops in the block, then the cursor is 
  434. positioned at the first such stop.  Hence you don't need to do this: set p 
  435. [getPos] ; insertText "blah..."  ; goto $p ; nextTabStop Instead you just do 
  436. 'elec::Insert "blah..."'.  Note that the procedure 'nextTabStop' no longer 
  437. exists.  Use "ring::+", "ring::-" etc.  to move amongst tab stops.  The 
  438. basic Alpha distribution contains only basic template support.  Install 
  439. Vince's Additions to extend this support to persistent stops, with 
  440. user-prompting in the text or status bar,...  You don't have to change your 
  441. code to take advantage of the features of V'sA. It comes for free if you use 
  442. 'elec::Insertion' etc.
  443.  
  444. If you wish to use electric templates, avoid binding anything to the 'tab' 
  445. key or the 'j' key (also opt-tab, cmd-tab,…).  Such bindings may conflict
  446. with the electric bindings.
  447.  
  448. To use electric templates, you'll want to add a mode preference for
  449. electricTab with 'newPref flag electricTab 1 <mode>'.  If your mode
  450. never wants the Tab key to indent, then define a dummy '<mode>::indentLine' 
  451. proc which is empty: 'proc <mode>::indentLine {} {}'.
  452.  
  453.              Electric return
  454.  
  455. This allows pressing return to indent correctly for the following line so 
  456. you may begin typing immediately.  To use this add a pref:
  457.  
  458.     newPref flag elecReturn 1 C++
  459.  
  460. and do not bind to the return key.
  461.  
  462.              Automatic indentation
  463.  
  464. Two variables are associated with a window's indentation scheme: 
  465. 'indentationAmount' and the window's tab-size (which can be read
  466. with 'getWinInfo' or 'text::getTabSize').  The flag 'indentFollowsTabs'
  467. declares whether the standard indentation shift is the tab-size (in
  468. which case 'indentationAmount' is ignored) or whether to follow that
  469. variable.  If you are writing a custom indentation routine, the
  470. procedure 'indent::setup' will be useful to handle all these choices
  471. for you.
  472.  
  473.              The marks menu
  474.  
  475. Each mode has a procedure <mode>::MarkFile which is called to create the
  476. popup 'M' menu of marks.  There is a global flag 'quietlyClearMarks'
  477. which is set to 1 which dictates that the marks should be rebuilt
  478. without prompting the user as necessary.  You can add a mode-pref
  479. to over-ride this if you want.
  480.  
  481.              <mode>Completions.tcl
  482.  
  483. Each mode can have a completions file for use by the 'elecCompletions' 
  484. package (part of Vince's Additions or available separately).  To use
  485. this, place the appropriate definitions in a file called 
  486. '<mode>Completions.tcl'.  The installer will place such files in the 
  487. 'Completions' directory automatically (provided you don't put them in 
  488. a sub-folder of your distribution), and they will also be sourced
  489. automatically the first time a file opens in your mode.  There is
  490. therefore no need for you to source the file yourself.
  491.  
  492. ===============================================================================
  493.  
  494.            Writing new menus
  495.  
  496. New menus are placed in ":Tcl:Menus", and contain a start-up
  497. section of much the same form as a mode:
  498.  
  499.     alpha::menu ftpMenu    0.3 "•141" in_menu {
  500.     }
  501.     # proc ftpMenu to auto-load
  502.     proc ftpMenu {} {}
  503.  
  504. The 'in_menu' paramter tells Alpha that this menu should go in the 
  505. 'package menus' menu for quick selection.  If the parameter is set to 
  506. any other value, the menu is not registered there (but can still be
  507. turned on or off using the Global->Menus dialog).
  508.  
  509. NOTE: If all you want to do is add a submenu to an already existing
  510. menu, go to the section 'Adding Items to Global Menus'.
  511.  
  512. A menu-package is a set of code which builds and handles a standalone menu 
  513. which the user may choose as a global menu.  Examples are the ftpMenu, 
  514. filesetMenu, voodooMenu, internetConfigMenu, colorMenu and eudoraMenu (in 
  515. fact this last item, since it has a mode associated with it, could in fact 
  516. be rewritten as a mode with attached menu).  Menus use a different startup
  517. scheme to extensions in that it is assumed a proc with the same name as the
  518. menu has been defined, and that calling that proc will build the menu.
  519. So the full setup will look like this
  520.  
  521.     alpha::menu ftpMenu    0.35 "•141" in_menu {} uninstall this-file
  522.     # proc ftpMenu to auto-load
  523.     proc ftpMenu {} {}
  524.     # ...
  525.  
  526. ===============================================================================
  527.  
  528.            Writing new extensions
  529.  
  530. A new extension must provide at the very least the following line, preferably 
  531. as the first non-comment line of one of its files:
  532.  
  533.     alpha::extension 'NAME' 'VERSION'
  534.     
  535. It is better, if possible, if the extension can provide a small script to 
  536. carry out initialisation (which occurs when Alpha starts up, if the user
  537. has turned the package on).  If provided Alpha will use that script 
  538. rather than sourcing the entire extension file.  This means Alpha will
  539. start up more quickly.  Such a script is given by the following line:
  540.  
  541.     alpha::extension 'NAME' 'VERSION' 'SCRIPT'
  542.     
  543. Here is an example from the 'bibtexEngine' package:
  544.  
  545.     alpha::extension bibtexEngine 1.6 {
  546.         eventHandler GURL GURL GURLHandler
  547.     }
  548.     
  549. The simple 'extension' command makes it very, very easy to extend Alpha's 
  550. functionality without messing with the user's preferences file, without 
  551. creating any '...+.tcl' extension files and without a complex installation 
  552. process.  Alpha simply maintains a database of all 'extension' scripts, and 
  553. evaluates at startup all scripts for extensions which the user has activated.
  554.  
  555.            Writing new extensions
  556.  
  557. Writers of any package for Alpha should pay some attention to the 
  558. problems which can arise with international keyboards.  Some bindings
  559. are simply not available on some keyboards.  For instance, on some
  560. keyboards, you need to use 'shift' to get the key '\' (unlike 
  561. american keyboards where it is a single keypress).  On such a keyboard
  562. there is no distinction between 'cmd-\' and 'shift-cmd-\'.  There is
  563. no simple workaround for this problem.
  564.  
  565. Possibilities are: (i) check the current keyboard definition and adjust
  566. bindings appropriately (based upon user feedback, presumably). (ii) let
  567. the bindings be user-definable either by using 'newPref binding' to
  568. define things, or by using a menu-scheme such as is used by HTML mode.
  569.  
  570. ===============================================================================
  571.            
  572.            Package preferences
  573.  
  574. Alpha stores preferences in three different places:
  575.  
  576. 1)    Global preferences are stored in the global->preferences menu, and
  577. are for variables/flags which maintain a value at the global scope.
  578.  
  579. 2)  Mode preferences are stored in the mode->preferences… item, and
  580. are for variables/flags which are stored in a mode array, but are transfered 
  581. into global scope when that mode is active (and hence temporarily override 
  582. any global preferences with the same names)
  583.  
  584. 3)  Packages may add to the global/mode preferences as they desire.  They 
  585. may also store preferences in their package array '${pkg}modeVars(…)'.  Such
  586. variables/flags are never transfered into the global scope.  Menu items to 
  587. edit a package's preferences should be placed in the 'global' menu, unless 
  588. they are global/mode prefs which should be added to Alpha's default 
  589. routines for use by the standard Alpha dialogs.  There is a standard proc
  590.  
  591.     package::addPrefsDialog Mypkg
  592.     
  593. which you can use to add an item to the global menu which will bring
  594. up the standard dialog to edit the contents of your '${pkg}modeVars(…)'
  595. array.
  596.  
  597.              Adding to the core prefs dialogs
  598.  
  599. If you wish to add items to any of the core preferences pages (Backups,
  600. Electric, Miscellaneous,...), you can do that like this:
  601.  
  602.     lunion varPrefs(Electric) var1 var2
  603.     lunion flagPrefs(Electric) flag1 flag2
  604.  
  605. All non-registered global preferences are added to the Miscellaneous page,
  606. so there is no need to do that automatically.  Make sure you don't add
  607. too much to any of these pages, because they will become too large to
  608. display correctly!
  609.  
  610. You can also add new core preferences pages.  All you have to do is create
  611. a new 'flagPrefs' entry (Alpha uses the command 'array names flagPrefs' to
  612. list the different pages):
  613.  
  614.     lunion flagPrefs(NewPage) flag1
  615.     
  616. Only add such pages if your package really does merit it; otherwise you're 
  617. better off just add a new global preferences dialog in the global menu.
  618.     
  619.              Defining a package's flags and variables
  620.  
  621. Preferences for a mode or package are defined as follows:
  622.  
  623.     newPref type name {val 0} {pkg "global"} {pname ""} \
  624.         {options ""} {subopt ""}
  625.  
  626. Define a new preference variable/flag.
  627.  
  628. 'type' is one of:
  629.   'flag' (on/off only), 'variable' (anything), 'binding' (key-combo)
  630.   'menubinding' (key-combo which works in a menu), 'file' (input only),
  631.   'io-file' (either input or output)
  632.   
  633. 'name' is the var name, 
  634.  
  635. 'val' is its default value (which will be ignored if the variable
  636. already has a value)
  637.  
  638. 'pkg' is either 'global' to mean a global preference, or the name 
  639. of the mode or package (no spaces) for which this is a preference.
  640.  
  641. 'pname' is a procedure to call if this preference is changed by
  642. the user (no need to setup a trace).  This proc is only called
  643. for changes made through prefs dialogs or prefs menus created by
  644. Alpha's core procs.  Other changes are not traced.
  645.  
  646. Depending on the previous values, there are two optional arguments
  647. with the following uses:
  648.  
  649. TYPE:
  650.  
  651. variable:
  652.  
  653. 'options' is a list of items from which this preference takes a single
  654. item.
  655. 'subopt' is any of 'item', 'index', 'varitem' or 'varindex' or 'array', where
  656. 'item' indicates the pref is simply an item from the given list
  657. of items, 'index' indicates it is an index into that list, and
  658. 'var*' indicates 'items' is in fact the name of a global variable
  659. which contains the list. 'array' means take one of the values from an array.
  660. If no value is given, 'item' is the default
  661.  
  662. binding:
  663.  
  664. 'options' is the name of a proc to which this item should be bound.
  665. If options = '1', then we bind to the proc with the same name as
  666. this variable.  Otherwise we do not perform automatic bindings.
  667.  
  668. 'subopt' indicates whether the binding is mode-specific or global.
  669. It should either be 'global' or the name of a mode.  If not given,
  670. it defaults to 'global' for all non-modes, and to mode-specific for
  671. all packages.  (Alpha tests if something is a mode by the existence
  672. of modeMenus($mode))
  673.  
  674. menubinding:
  675.  
  676. menubindings are like bindings, but they don't have any automatic
  677. binding capabilities, and are restricted to key-sequences which the
  678. MacOS allows in menus.  Here is an example of how one might declare
  679. the 'QuickFind(Regexp)' dynamic pair using a menubinding pref:
  680.  
  681. declare the binding:
  682.  
  683.     «Alpha ƒ» newPref menubinding quickFind/quickFindRegexp <B/S
  684.     
  685. edit it if we like with:
  686.  
  687.     «Alpha ƒ» dialog::getAKey quickFind/quickFindRegexp <B/S
  688.     
  689. show the menu sequence if we like:
  690.     
  691.     «Alpha ƒ» menu::bind quickFind/quickFindRegexp -
  692.     <S<E<B/SquickFind <S<I<B/SquickFindRegexp
  693.     «Alpha ƒ» 
  694.  
  695. add it to a menu:
  696.  
  697.     «Alpha ƒ» eval menu::insert Search items end \
  698.         [menu::bind quickFind/quickFindRegexp -]
  699.     
  700. Have a look at the search menu.  It has a new dynamic item at the bottom!
  701.  
  702.            Adding items to global menus
  703.  
  704. Using 'addMenuItem' is a bad idea, since many menus are dynamically
  705. rebuilt and such items will be lost.  Furthermore, addMenuItem does
  706. not work if you want to add dynamic items or sub-menus.  Also
  707. creating a menu directly using 'menu -n Name {list of items}' is
  708. generally a bad thing to do when using Alpha version 7.0 or newer.
  709.  
  710. The solution to these problems is to use the following calls:
  711.  
  712.     menu::buildProc 'menu' 'procname' 
  713.     menu::insert 'menu' 'type' 'where' 'item' ?item...?
  714.  
  715. For technical reasons, if you use both types of call, always add the procs 
  716. first.  You can add any list of items using the latter of these two calls.  
  717. The first registers a procedure which will be called to build a given menu.
  718.  
  719. Menus must be rewritten to support this new feature.  Currently all 
  720. global menus File...Config support it, and several modes: Tcl, Perl, 
  721. TeX.
  722.  
  723.              menu::buildProc
  724.  
  725. Register a procedure to be the 'build proc' for a given menu.  This
  726. procedure can do one of two things:
  727.  
  728. i) build the entire menu, including evaluating the 'menu ...' command.
  729. In this case the build proc should return anything which doesn't
  730. begin 'build ...'  If the proc returns anything beginning with 
  731. 'menu ..' that returned string is evaluated, but no insertions can
  732. take place.
  733.  
  734. ii) build up part of the menu, and then allow pre-registered menu
  735. insertions/replacements to take-effect.  In this case the procedure
  736. should return a list of the following (listed by index in the list):
  737.  
  738. 0: "build"
  739. 1: list-of-items-in-the-menu
  740. 2: menu procedure to call when an item is selected.  If nothing is given,
  741. or if '-1' is given, then we don't have a procedure.  If "" is given,
  742. we use the standard 'menu::generalProc' procedure.  Else we use the
  743. given procedure.
  744. 3: list of submenus which need building.
  745. 4: over-ride for the name of the menu.
  746.  
  747. You must register the build-proc before attempting to build the menu.
  748. Once registered, any call of 'menu::buildSome name' will build your
  749. menu.
  750.  
  751.              menu::insert
  752.  
  753. name, type, where, then list of items.  type = 'items' 'submenu'
  754.  
  755. Add given items to a given menu, provided they are not already there.
  756. Rebuild that menu if necessary.
  757.  
  758. There are also procs 'menu::removeFrom' which does the opposite of
  759. this one, and 'menu::replaceWith' which replaces a given menu item
  760. with others.
  761.  
  762. There is a difference between 'menu::insert Utils submenu 2 compare' and 
  763. 'menu::insert Utils items 2 [list menu -n compare {}]'.  The former 
  764. registers the submenu as a submenu which will be built automatically by a 
  765. call to 'menu::buildSome' each time the parent menu is rebuilt, the latter 
  766. does no such thing.  You will, therefore normally wish to use the first 
  767. form, but occasionally there will be situations when the latter would be 
  768. better.
  769.  
  770. Here is a simple example:
  771.  
  772.     alpha::extension compareWindows 0.1 {
  773.         bind 0x32    <X> compare::windowsInPlace
  774.         bind '1'  <X> compareOpt
  775.         bind 0x32    <sX> compareNext
  776.         bind 0x12    <sX> compareOptNext
  777.         menu::insert Utils submenu 2 compare
  778.         menu::insert "compare" items end windowsInPlace
  779.     }
  780.  
  781. We first add a submenu after the second item in the Utils menu, called
  782. 'compare', and then add to the end of that compare menu. This code works 
  783. whether the package is active at startup or not.  Here is a more 
  784. complex example:
  785.  
  786.     alpha::extension documentProjects 1.2 {
  787.         alpha::package require elecCompletions
  788.         alpha::package require newDocument
  789.         menu::buildProc "Current Project" Docproj::currentMenu
  790.         menu::insert global items end \
  791.             "documentProjectPrefs…" "userDetails…" \
  792.             "<E<SremoveDocumentTemplate…" "<S<BeditDocumentTemplate…" \
  793.             "<SnewDocumentTemplate…" \
  794.             "<E<SremoveProject…" "<S<BeditProject…" "<SnewProject…"
  795.         menu::insert global submenu end {Current Project}
  796.         newPref binding updateFileVersion "/f<U" Docproj
  797.         menu::insert fileUtils items end \
  798.             "showInFinder" \
  799.             "(-" \
  800.             "updateDate" \
  801.             "[menu::bind DocprojmodeVars(updateFileVersion) -]"
  802.         lunion elec::MenuTemplates "createHeader" "newDocument"
  803.         menu::insert elec items end \
  804.             {menu -n functionComments -p menu::fileUtils {
  805.             "/efunctionComment"    
  806.             "/e<IfunctionCommentSimple" 
  807.             "/e<OfunctionCommentWithAuthor" 
  808.             "/e<UfunctionCommentUpdate" 
  809.         }}
  810.         set newDocument::handlers(documentProjects) Docproj::newHandler
  811.     }
  812.  
  813. The 'documentProjects' package adds items to many different menus,
  814. including the 'elec' menu (from the elecCompletions package).
  815.  
  816. ===============================================================================
  817.  
  818.            Package testing
  819.  
  820. The 'alpha::package' command is very similar to Tcl 8.0's standard
  821. 'package' command, but differs in a few respects.  When Alpha upgrades
  822. to Tcl 8, this will allow both features to coexist happily.  You can use
  823. 'alpha::package' to check/request the presence of other packages.
  824.  
  825.     alpha::package require NAME ?VERSION?
  826.     
  827. Other sub-commands are 'exists' 'names' 'versions' 'vcompare' 'vsatisfies'
  828. 'forget' 'uninstall' and 'mode', 'menu' and 'package'.  These last three
  829. mimic the usual alpha::mode alpha::menu and alpha::package commands.
  830.  
  831.     alpha::package require ?-extension -mode -menu? name version
  832.     alpha::package exists ?-extension -mode -menu? name version
  833.     alpha::package names
  834.     alpha::package uninstall name version [this-file|this-directory|script]
  835.     alpha::package vcompare v1 v2
  836.     alpha::package vsatisfies v1 v2
  837.     alpha::package versions ?-extension -mode -menu? name
  838.     alpha::package type name
  839.     alpha::package info name
  840.     alpha::package maintainer name version {name email web-page}
  841.     alpha::package help name version [file 'name'|text]
  842.  
  843. Equivalent to alpha::mode, alpha::menu and alpha::extension
  844.  
  845.     alpha::package mode ...
  846.     alpha::package menu ...
  847.     alpha::package extension ...
  848.  
  849. For extensions only:
  850.  
  851.     alpha::package forget name version
  852.  
  853. ..
  854.  
  855. ===============================================================================
  856.  
  857.            Installation
  858.  
  859. There is a new install mode 'Inst' which adds the Install menu.
  860. Install mode is trigerred when a file's name ends in 'Install'
  861. or 'INSTALL', or when the first line of the file contains the
  862. letters 'install', provided in this last case, that the file
  863. is not in Alpha's Tcl hierarchy.  This last case is useful so
  864. that a single .tcl file can be a package and be installed by
  865. Alpha using these nice scripts, without the need for a separate
  866. install-script-file.  However once that .tcl file is installed,
  867. if you open it you certainly wouldn't want it opened in Install mode!
  868.     
  869. So, single file packages should just include 'install' somewhere in
  870. their first line.  Multi-file packages should include an install
  871. file.  Call this file 'OPEN TO INSTALL' or something like that.
  872. When the user opens it, Inst mode is activated, and the user can
  873. use the install menu to install your package.  If you wish the
  874. installation dialog to be activated automatically, include the
  875. text (auto-install) in the first line of the file.
  876.  
  877. Most packages will _not_ need anything other than the existence of
  878. such a file.  In fact a file called 'OPEN TO INSTALL' containing the
  879. single line '(auto-install)' will do the trick nicely.
  880.  
  881. Alpha will scan the installation file directory and make a nice
  882. dialog with 'Easy install' and 'Custom install' options.  Alpha
  883. knows where Modes, Menus, Completions, Bug fixes, Tools, Packages,
  884. Extensions, ... all go in the Alpha hierarchy.
  885.  
  886.              Package-specific installation over-rides
  887.  
  888. You can over-ride the default behaviour by providing a 'xxx_install.tcl'
  889. file in the file directory.  In such a case that file will be sourced.
  890. See "install.tcl" for some more information on how to over-ride the
  891. default behaviour.  You will usually use the following procedure:
  892.  
  893.     install::packageInstallationDialog 'NAME' 'DESCRIPTION' ...
  894.  
  895. Optional arguments are as follows:
  896.  
  897.     -ignore {list of files to ignore}
  898.     -remove {list of files to remove from Alpha hierarchy}    
  899.     -forcequit '0 or 1'  
  900.         (forces the user to quit; default 0)
  901.     -require {Pkg version Pkg version …}
  902.         e.g. -require {Alpha 7.0b1p2 elecCompletions 7.99}
  903.     -provide {Pkg version Pkg version …}
  904.  
  905. and 
  906.  
  907.     -SystemCode -Modes -Menus -BugFixes -Completions -Packages
  908.     -ExtensionsCode -UserModifications -Tools -Home
  909.  
  910. which force the placement/use of the following lists of files.  To
  911. require an exact package version use:
  912.  
  913.     -require {Alpha {-exact 7.0b2} elecCompletions {-exact 8.1.2} ...}
  914.  
  915. Also, rather than having separate 'OPEN-TO-INSTALL' and '*install.tcl'
  916. files, if the former file contains the text 'auto-install-script' in
  917. its first line, it will be used as a Tcl script, and sourced rather than
  918. opened.  Ensure that first line begins with a '#' or an error will
  919. result.  (You can open that file for editing, without triggering the
  920. install script if you hold down a modifier key).
  921.  
  922. If you gave the -provide option, Alpha checks those items with what
  923. the user has already installed and warns if an item has already been 
  924. installed and is not older than the one about to be installed.
  925.  
  926.              Uninstalling packages
  927.  
  928. Each package should provide a 'alpha::package uninstall name version script' 
  929. statement.  When your script is evaluated, the global variable 'pkg_file' 
  930. will be initialised to the full name of the file which contains the 
  931. uninstall command.  Therefore for a single file package, the following is 
  932. normal:
  933.  
  934.     alpha::package uninstall developerUtilities 1.1 {removeFile $pkg_file}
  935.  
  936. However, a much more convenient form of the above command is also possible, 
  937. and most packages use it --- you may combine declaration and uninstall lines 
  938. like this:
  939.  
  940.     alpha::extension developerUtilities 1.1 {
  941.         # declaration script
  942.     } uninstall {
  943.         # uninstall script
  944.     }
  945.     
  946. i.e. there are two extra optional arguments to the 'package' command.
  947. Finally to be even simpler, if the command is 'uninstall this-file',
  948. then that is equivalent to {removeFile $pkg_file}, and if the command
  949. is 'uninstall this-directory', then that entire file's directory is
  950. removed.  Make sure you don't use 'uninstall this-directory' for a
  951. single-file package, or you'll wipe out the entire package hierarchy.
  952. Similarly alpha::mode and alpha::menu commands may contain an optional
  953. uninstall script like the above.
  954.  
  955.              Disabling packages
  956.  
  957. A package can add a script to be evaluated when the user disables the
  958. package.  You do that with the additional command 'disable':
  959.  
  960.     alpha::extension developerUtilities 1.1 {
  961.         # declaration script
  962.     } disable {
  963.         # disable script
  964.     }
  965.  
  966. Complex packages will probably not provide such a script.  In such a
  967. case the user would have to restart Alpha to disable the package
  968. correctly.
  969.  
  970.              Tcl index files
  971.  
  972. You probably know that Tcl uses 'index' files to find procedures which
  973. are called but not yet defined.  Your installation directories may
  974. contain index files if you desire, but they are only installed if no
  975. current index file exists in the installation location.  You cannot
  976. override this behaviour.
  977.  
  978. ===============================================================================
  979.            
  980.            Vince's Additions Support:
  981.  
  982. This is primarily for new modes. 
  983.  
  984.              Source-Header files
  985.      
  986. If your mode makes distinctions between 'Source' and 'Header' 
  987. files, you should define these two variables
  988.  
  989.     newPref var sourceSuffices { .cc .cp .cpp .c .icc } C++
  990.     newPref var headerSuffices { .h .hh } C++
  991.  
  992.              Completions
  993.  
  994. If you mode is to use a variety of completion routines, define
  995. an array entry like this:
  996.  
  997.     set completions(${mode}) \
  998.         {completion::cmd completion::electric completion::word}
  999.  
  1000. For the meaning of the list items, look at "elecCompletion.tcl".  If
  1001. all you need is the basic 'Command', 'Electric' and 'Word' completion
  1002. routines, the above list will do the trick.  You will then need to
  1003. define a variable ${mode}cmds like this:  
  1004.  
  1005.     set Ccmds { #elseif #endif #include class default enum for register return 
  1006.      struct switch typedef volatile while }
  1007.  
  1008. It MUST be in alphabetical order, and both start and end with a 
  1009. whitespace character.  For electric template insertions, you need
  1010. to create an array with entries like these:
  1011.     
  1012.     set Celectrics(for) " (•init•;•test•;•increment•)\{\n\t•loop body•\n\}\n••"
  1013.     set Celectrics(while) " (•test•)\{\n\t•loop body•\n\}\n••"
  1014.     set Celectrics(switch) " (•value•)\{\n…case •item•:\n\t•case body•\n…default:\n\t•default body•\n\}\n••"
  1015.     set Celectrics(case) " •item•:\n…•case body•\ncase"
  1016.  
  1017.              Mode-specific completions
  1018.  
  1019. If your mode has its own completion routines, they must be named
  1020. ${mode}::Completion::Type, where 'Type' is an entry in the above
  1021. list.  You'll have to know a reasonable bit of Tcl to write your
  1022. own routines like that.  Look at C::Completion::Class for a relatively
  1023. simple example.
  1024.  
  1025.              Electric menu templates
  1026.  
  1027. ${mode}Templates is a list of names which are added to the electric 
  1028. menu's 'Templates' sub-menu.  The real procs should be called 
  1029. 'file::${name}'.
  1030.  
  1031.              Vince's Additions summary
  1032.  
  1033. That's it!  Take a look at "scilabMode.tcl" as a simple example of a new mode
  1034. which makes use of Vince's Additions.
  1035.  
  1036. ===============================================================================
  1037.  
  1038.